@page "/admin/identityResources"
@attribute [Authorize(Policies.IsAdmin)]
@layout AdminLayout
@inject HttpClient Http
@inject IViewNotifier viewNotifier
@inject IStringLocalizer<Global> L

@using IdentityServer4.Models
@using IdentityModel
@using System.Net

<h1>@L["IdentityResources"]</h1>
<p>Identity Resources Management.</p>

@if (identiyResources == null)
{
    <LoadingBackground ShowLogoBox="true">
        <label>@L["Loading"]</label>
    </LoadingBackground>
}
else
{
    <MatTable Class="mat-elevation-z5" Items="@identiyResources" Striped="true">
        <MatTableHeader>
            <th><MatButton Icon="add" Label=@L["New Identity Resource"] OnClick="@(() => OpenUpsertIdentityResourceDialog())"></MatButton></th>
            <th>@L["Name"]</th>
            <th>Enabled</th>
            <th>Display Name</th>
            <th>Description</th>
            <th>Required</th>
            <th>Emphasize</th>
            <th>Show in discovery document</th>
            <th>User Claims</th>
        </MatTableHeader>
        <MatTableRow Context="IdentityResourceRow">
            <td>
                <div style="width:155px;">
                    <MatIconButton Icon="edit" OnClick="@(() => OpenUpsertIdentityResourceDialog(IdentityResourceRow))"></MatIconButton>
                    <MatIconButton Icon="delete" OnClick="@(() => OpenDeleteIdentityResourceDialog(IdentityResourceRow))"></MatIconButton>
                </div>
            </td>
            <td><div style="min-width:130px;">@IdentityResourceRow.Name</div></td>
            <td><MatSlideToggle TValue="bool" Value="@IdentityResourceRow.Enabled" ValueChanged="@((item) => UpdateEnabled(IdentityResourceRow))"></MatSlideToggle></td>
            <td><div style="min-width:130px;">@IdentityResourceRow.DisplayName</div></td>
            <td><div style="min-width:130px;">@IdentityResourceRow.Description</div></td>
            <td><MatSlideToggle TValue="bool" Value="@IdentityResourceRow.Required" Disabled="true"></MatSlideToggle></td>
            <td><MatSlideToggle TValue="bool" Value="@IdentityResourceRow.Emphasize" Disabled="true"></MatSlideToggle></td>
            <td><MatSlideToggle TValue="bool" Value="@IdentityResourceRow.ShowInDiscoveryDocument" Disabled="true"></MatSlideToggle></td>
            <td>
                <MatChipSet>
                    @foreach (var userClaim in IdentityResourceRow.UserClaims)
                        {
                        <MatChip Label="@userClaim"></MatChip>
                        }
                </MatChipSet>
            </td>
        </MatTableRow>
    </MatTable>
}

<MatDialog @bind-IsOpen="@isUpsertIdentityResourceDialogOpen">
    <MatDialogTitle>
        @labelUpsertDialogTitle
    </MatDialogTitle>
    <MatDialogContent>
        <EditForm Model="@currentIdentityResource">
            <FluentValidationValidator />
            <ValidationSummary />
            <MatTabGroup>
                <MatTab Label="Main">
                    <fieldset>
                        <div class="form-group">
                            <MatTextField @bind-Value="@currentIdentityResource.Name" Disabled="@isCurrentIdentityContextIdReadOnly" Label="Id" Icon="description" IconTrailing="true" FullWidth="true" Required="true"></MatTextField>
                        </div>
                        <div class="form-group">
                            <MatSlideToggle @bind-Value="@currentIdentityResource.Enabled" Label="Enabled"></MatSlideToggle>
                        </div>
                        <div class="form-group">
                            <MatTextField @bind-Value="@currentIdentityResource.DisplayName" Label="Display Name" Icon="description" IconTrailing="true" FullWidth="true"></MatTextField>
                        </div>
                        <div class="form-group">
                            <MatTextField @bind-Value="@currentIdentityResource.Description" Label="Description" Icon="description" IconTrailing="true" FullWidth="true"></MatTextField>
                        </div>
                        <div class="form-group">
                            <MatSlideToggle @bind-Value="@currentIdentityResource.Required" Label="Required"></MatSlideToggle>
                        </div>
                        <div class="form-group">
                            <MatSlideToggle @bind-Value="@currentIdentityResource.Emphasize" Label="Emphasize in consent screen"></MatSlideToggle>
                        </div>
                        <div class="form-group">
                            <MatSlideToggle @bind-Value="@currentIdentityResource.ShowInDiscoveryDocument" Label="Show in discovery document"></MatSlideToggle>
                        </div>
                    </fieldset>
                </MatTab>
                <MatTab Label="User Claims">
                    <fieldset>
                        <div class="form-group" style="margin-top:16px;">
                            <div class="form-group">
                                <MatTextField @bind-Value="@currentIdentityResource.CustomUserClaimsText" Label="Custom User Claims" TextArea="true" FullWidth="true" Required="false"></MatTextField>
                            </div>
                        </div>
                    </fieldset>
                    <MatDivider></MatDivider>
                    <h3 class="mat-subtitle1">Jwt Claims</h3>
                    <MatTable Items="@jwtClaimSelections" Class="mat-elevation-z5, mdc-table-allow" ShowPaging="false" PageSize="@int.MaxValue">
                        <MatTableHeader>
                            <th>@L["Name"]</th>
                            <th>Required</th>
                        </MatTableHeader>
                        <MatTableRow Context="JwtClaimRow">
                            <td>@JwtClaimRow.Name</td>
                            <td><MatCheckbox TValue="bool" @bind-Value="@JwtClaimRow.IsSelected"></MatCheckbox></td>
                        </MatTableRow>
                    </MatTable>
                </MatTab>
            </MatTabGroup>
        </EditForm>
    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@CancelChanges">@L["Cancel"]</MatButton>
        <MatButton OnClick="@UpsertIdentityResource">@labelUpsertDialogOkButton</MatButton>
    </MatDialogActions>
</MatDialog>

<MatDialog @bind-IsOpen="@isDeleteIdentityResourceDialogOpen" Style="z-index:100">
    <MatDialogTitle><MatIcon Icon="warning"></MatIcon> @L["Confirm Delete"]</MatDialogTitle>
    <MatDialogContent>
        @L["Are you sure you want to delete {0}?", currentIdentityResource.Name]
    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@(e => { isDeleteIdentityResourceDialogOpen = false; })">@L["Cancel"]</MatButton>
        <MatButton OnClick="@DeleteIdentityResourceAsync">@L["Delete"]</MatButton>
    </MatDialogActions>
</MatDialog>

@code {
    int pageSize { get; set; } = 15;
    int currentPage { get; set; } = 0;

    bool isCurrentIdentityContextIdReadOnly = false;

    List<IdentityResourceDto> identiyResources;
    IdentityResourceDto currentIdentityResource { get; set; } = new IdentityResourceDto();
    Secret currentSecret { get; set; } = new Secret();

    #region OnInitializedAsync

    protected override async Task OnInitializedAsync()
    {
        await InitializeIdentityResourcesListAsync();
    }

    public async Task InitializeIdentityResourcesListAsync()
    {
        try
        {
            var identiyResponse = await Http.GetNewtonsoftJsonAsync<ApiResponseDto<List<IdentityResourceDto>>>($"api/Admin/IdentityResources?pageSize={pageSize}&pageNumber={currentPage}");

            if (identiyResponse.IsSuccessStatusCode)
            {
                viewNotifier.Show(identiyResponse.Message, ViewNotifierType.Success, L["Operation Successful"]);
                identiyResources = identiyResponse.Result;
            }
            else
                viewNotifier.Show(identiyResponse.Message, ViewNotifierType.Error, L["Operation Failed"]);
        }
        catch (Exception ex)
        {
            viewNotifier.Show(ex.GetBaseException().Message, ViewNotifierType.Error, L["Operation Failed"]);
        }
    }

    #endregion

    #region OpenUpsertIdentityResourceDialog

    class Selection
    {
        public bool IsSelected { get; set; }
        public string Name { get; set; }
        public string Value { get; set; }
    };

    bool isUpsertIdentityResourceDialogOpen = false;
    bool isInsertOperation;

    string labelUpsertDialogTitle;
    string labelUpsertDialogOkButton;
    List<Selection> jwtClaimSelections = new List<Selection>();


    void OpenUpsertIdentityResourceDialog(IdentityResourceDto identiyResource = null)
    {
        try
        {
            isInsertOperation = identiyResource == null;

            currentIdentityResource = identiyResource ?? new IdentityResourceDto();

            // Update the UI
            if (isInsertOperation)
            {
                labelUpsertDialogTitle = L["New Identity Resource"];
                labelUpsertDialogOkButton = L["Create"];
            }
            else
            {
                labelUpsertDialogTitle = L["Edit {0}", currentIdentityResource.Name];
                labelUpsertDialogOkButton = L["Update"];
            }

            isCurrentIdentityContextIdReadOnly = !isInsertOperation;

            jwtClaimSelections.Clear();

            foreach (var info in typeof(JwtClaimTypes).GetFields().Where(x => x.IsStatic && x.IsLiteral))
            {
                jwtClaimSelections.Add(new Selection
                {
                    Name = $"{info.Name.Humanize(LetterCasing.Title)} ({info.GetValue(info)})",
                    Value = info.GetValue(info).ToString(),
                    IsSelected = currentIdentityResource.UserClaims.Contains(info.GetValue(info))
                });
            }

            currentIdentityResource.CustomUserClaims = currentIdentityResource.GetCustomUserClaims().ToList();

            if (!isInsertOperation)
                currentIdentityResource.SaveState();

            isUpsertIdentityResourceDialogOpen = true;
        }
        catch (Exception ex)
        {
            viewNotifier.Show(ex.GetBaseException().Message, ViewNotifierType.Error, L["Operation Failed"]);
        }
    }

    async Task UpdateEnabled(IdentityResourceDto identiyResource)
    {
        currentIdentityResource = identiyResource;
        currentIdentityResource.Enabled = !currentIdentityResource.Enabled;
        isInsertOperation = false;
        await UpsertIdentityResource();
    }

    void CancelChanges()
    {
        currentIdentityResource.RestoreState();
        isUpsertIdentityResourceDialogOpen = false;
    }

    async Task UpsertIdentityResource()
    {
        try
        {
            if (currentIdentityResource == null)
            {
                viewNotifier.Show("IdentityResource Creation Error", ViewNotifierType.Error, "New Identity Resource not found");
                return;
            }

            if (isUpsertIdentityResourceDialogOpen)
            {
                currentIdentityResource.UserClaims = jwtClaimSelections.Where(i => i.IsSelected).Select(i => i.Value).ToList();
                ((List<string>)currentIdentityResource.UserClaims).AddRange(currentIdentityResource.CustomUserClaims);
            }

            ApiResponseDto identiyResponse;

            if (isInsertOperation)
                identiyResponse = await Http.PostJsonAsync<ApiResponseDto>("api/Admin/IdentityResource", currentIdentityResource);
            else
                identiyResponse = await Http.PutJsonAsync<ApiResponseDto>("api/Admin/IdentityResource", currentIdentityResource);

            if (identiyResponse.IsSuccessStatusCode)
            {
                viewNotifier.Show(identiyResponse.Message, ViewNotifierType.Success);

                StateHasChanged();
            }
            else
                viewNotifier.Show(identiyResponse.Message, ViewNotifierType.Error);


            await OnInitializedAsync();

            isUpsertIdentityResourceDialogOpen = false;
        }
        catch (Exception ex)
        {
            viewNotifier.Show(ex.GetBaseException().Message, ViewNotifierType.Error, L["Operation Failed"]);
        }
        finally
        {
            currentIdentityResource.ClearState();
        }
    }

    #endregion

    #region OpenDeleteIdentityResourceDialog

    bool isDeleteIdentityResourceDialogOpen = false;

    void OpenDeleteIdentityResourceDialog(IdentityResourceDto identiyResource)
    {
        currentIdentityResource = identiyResource;
        isDeleteIdentityResourceDialogOpen = true;
    }

    async Task DeleteIdentityResourceAsync()
    {
        try
        {
            var response = await Http.DeleteAsync($"api/Admin/IdentityResource/{currentIdentityResource.Name}");
            if (response.StatusCode != (HttpStatusCode)Status200OK)
            {
                viewNotifier.Show("Identity Resource Delete Failed", ViewNotifierType.Error);
                return;
            }

            viewNotifier.Show("Identity Resource Deleted", ViewNotifierType.Success);
            await OnInitializedAsync();
            isDeleteIdentityResourceDialogOpen = false;
            StateHasChanged();
        }
        catch (Exception ex)
        {
            viewNotifier.Show(ex.GetBaseException().Message, ViewNotifierType.Error, L["Operation Failed"]);
        }
    }

    #endregion
}
